#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <termios.h>
#include <errno.h>
#include <gpio.h>

#define BUF_SIZE 1024  // 缓冲区大小

// 定义一个结构体来存储GPS数据
typedef struct {
    char time[11];
    char latitude[10];
    char longitude[11];
    char OK[10];
    char Number_satellites[10];
    char HDOP[10];
    char altitude[10];
    char geoid_height[10];
    char ID[10];
} GPSData;

static int fd_cloud; // 云平台串口终端对应的文件描述符
static int fd_gps;   // GPS串口终端对应的文件描述符

// 串口初始化操作
static int uart_init(const char *device, int baud_rate, int *fd) {
    *fd = open(device, O_RDWR | O_NOCTTY);  // 以读写方式打开串口，不控制终端
    if (*fd < 0) {
        perror("open error");  // 打开失败，打印错误信息
        return -1;  // 返回-1表示初始化失败
    }

    struct termios options;
    tcgetattr(*fd, &options); // 获取当前串口配置

    // 设置为原始模式，不进行输入/输出处理
    cfmakeraw(&options);

    // 设置波特率
    cfsetispeed(&options, baud_rate);

    // 清除输入处理相关的标志位
    options.c_iflag &= ~(IXON | IXOFF | IXANY);

    // 清除输出处理，不进行输出后处理
    options.c_oflag &= ~OPOST;

    // 禁用ECHO、ISIG等本地模式标志位
    options.c_lflag &= ~(ECHO | ECHOE | ISIG);

    // 设置阻塞读取，直到有数据可读
    options.c_cc[VMIN] = 1;
    options.c_cc[VTIME] = 0;  // 不设置超时时间

    if (tcsetattr(*fd, TCSANOW, &options) < 0) {
        perror("tcsetattr error");  // 设置串口属性失败，打印错误信息
        return -1;  // 返回-1表示初始化失败
    }

    return 0;  // 初始化成功，返回0
}

// 从串口读取数据
static ssize_t read_from_serial(int fd, char *buffer, size_t bufsize) {
    ssize_t bytesRead = 0;  // 读取到的字节数
    char c;  // 单个字符变量
    while (bytesRead < bufsize - 1) {  // 确保至少留下一个字节给字符串结束符
        ssize_t n = read(fd, &c, 1);  // 从串口读取一个字符
        if (n < 0) {
            perror("read failed");  // 读取失败，打印错误信息
            return -1;  // 返回-1表示读取失败
        } else if (n == 0) {
            continue;  // 没有数据可读，继续循环
        }
        buffer[bytesRead++] = c;  // 将读取到的字符存入缓冲区，并更新已读取的字节数
        if (c == '\n' || c == '\r') {  // 遇到换行符或回车符，认为是一行数据的结束
            break;
        }
    }
    buffer[bytesRead] = '\0';  // 在缓冲区末尾添加空字符，形成字符串
    return bytesRead;  // 返回读取到的字节数
}

// 解析GNRMC数据
static int parse_gnrmc_data(const char *data, GPSData *gpsData) {
    if (strncmp(data, "$GNGGA", 6) != 0) {     // 不是GNRMC数据，直接返回
        return -1;
    }

    char *token;
    char *context = NULL;
    int field = 0;

    token = strtok_r((char *) data, ",", &context);  // 使用逗号作为分隔符来分解数据
    while (token != NULL) {
        switch (field) {
            case 1:  // 时间
                strncpy(gpsData->time, token, 10);
                gpsData->time[10] = '\0';
                break;
            case 2:  // 纬度
                strncpy(gpsData->latitude, token, 9);
                gpsData->latitude[9] = '\0';
                break;
            case 4:  // 经度
                strncpy(gpsData->longitude, token, 10);
                gpsData->longitude[10] = '\0';
                break;
            case 6:  // 判断数据是否有效
                strncpy(gpsData->OK, token, 10);
                gpsData->OK[10] = '\0';
                break;
            case 7: // 有几颗卫星
                strncpy(gpsData->Number_satellites, token, 10);
                gpsData->Number_satellites[10] = '\0';
                break;
            case 8: // 水平精度因子
                strncpy(gpsData->HDOP, token, 10);
                gpsData->HDOP[10] = '\0';
                break;
            case 9: // 海拔高度
                strncpy(gpsData->altitude, token, 10);
                gpsData->altitude[10] = '\0';
                break;
            case 10: // 大地水准面高度
                strncpy(gpsData->geoid_height, token, 10);
                gpsData->geoid_height[10] = '\0';
                break;
            case 11: // 差分站ID
                strncpy(gpsData->ID, token, 10);
                gpsData->ID[10] = '\0';
                break;
            default:
                break;
        }
        field++;
        token = strtok_r(NULL, ",", &context);  // 继续分解下一个字段
    }
    return 0;
}

// 向串口写入数据
static ssize_t write_to_serial(int fd, const char *data, size_t len) {
    ssize_t bytesWritten = write(fd, data, len);
    if (bytesWritten < 0) {
        perror("write failed");
        return -1; // 写入失败，返回-1
    }
    return bytesWritten; // 返回写入的字节数
}

// 发送AT命令并接收响应的辅助函数
char *send_at_command(int serial_fd, const char *at_command, int timeout_seconds) {
    write(serial_fd, at_command, strlen(at_command)); // 发送AT命令
    fd_set readfds;
    struct timeval tv;
    char buffer[BUF_SIZE];
    int select_result, bytes_read = 0;
    memset(buffer, 0, BUF_SIZE);

    while (1) {
        FD_ZERO(&readfds);
        FD_SET(serial_fd, &readfds);

        tv.tv_sec = timeout_seconds;
        tv.tv_usec = 0;

        select_result = select(serial_fd + 1, &readfds, NULL, NULL, &tv);

        if (select_result == -1) {
            perror("select() error");
            break;
        } else if (select_result > 0) {
            int rd = read(serial_fd, &buffer[bytes_read], BUF_SIZE - bytes_read - 1);
            if (rd > 0) {
                bytes_read += rd;
            } else if (rd == 0 || (rd == -1 && errno != EINTR && errno != EAGAIN)) {
                break;
            }
        } else {
            break;
        }
    }

    buffer[bytes_read] = '\0';
    char *response = strdup(buffer);
    return response;
}

int main(int argc, char *argv[]) {
    const char *device_cloud = "/dev/ttymxc1";  // 云平台串口设备，根据实际情况修改
    const char *device_gps = "/dev/ttymxc2";    // GPS串口设备，根据实际情况修改

    char buffer[BUF_SIZE];
    GPSData gpsData; //存放信息的结构体

    // 初始化云平台串口
    if (uart_init(device_cloud, B115200, &fd_cloud)) {
        return 1;  // 初始化失败，返回1
    }

    // 初始化GPS串口
    if (uart_init(device_gps, B38400, &fd_gps)) {
        return 1;  // 初始化失败，返回1
    }

    // 存放数据的两个buffer
    char buffer_cloud[BUF_SIZE]; // 存放云平台的
    char buffer_gps[BUF_SIZE]; // 存放gps的

/********************云平台的参数定义区**************************/
    // 定义MQTT 参数  (这里的参数改成自己的)
    const char *clientId = "h8w1VFUhcS3.share_car|securemode=2\\,signmethod=hmacsha256\\,timestamp=1718352407501|";  //这里也需要改
    const char *username = "your_username";
    const char *passwd = "your_passwd";
    const char *mqttHostUrl = "iot-06z00hohrg7s730.mqtt.iothub.aliyuncs.com";  //这里也改
    int port = 1883;

    const char *mqtt_topic_sub_set = "/sys/h8w1VFUhcS3/share_car/thing/service/property/set"; //这里也该
    const char *mqtt_topic_sub_post = "/sys/h8w1VFUhcS3/share_car/thing/event/property/post_reply"; ///这里也改

    // 定义WiFi名称、密码
    const char *wifi_ssid = "dhdh2"; //改成自己的热点
    const char *wifi_password = "123456dh"; //改成自己的热点

    // 定义用于存储AT命令的字符数组
    const char *at = "AT\r\n"; //
    const char *at_rst = "AT+RST\r\n";
    const char *at_cwmode = "AT+CWMODE=1\r\n"; // 您要发送的AT命令
    char at_cwjap[128];

    char at_mqtt_usercfg[256];
    char at_mqtt_clientid[256];
    char at_mqtt_conn[256];
    char at_mqtt_sub_set[128];
    char at_mqtt_sub_post[128];
    char at_mqtt_pub_post[512];

    // 使用sprintf构建AT命令
    sprintf(at_cwjap, "AT+CWJAP=\"%s\",\"%s\"\r\n", wifi_ssid, wifi_password);

    sprintf(at_mqtt_usercfg, "AT+MQTTUSERCFG=0,1,\"\",\"%s\",\"%s\",0,0,\"\"\r\n", username, passwd);
    sprintf(at_mqtt_clientid, "AT+MQTTCLIENTID=0,\"%s\"\r\n", clientId);
    sprintf(at_mqtt_conn, "AT+MQTTCONN=0,\"%s\",%d,1\r\n", mqttHostUrl, port);

    sprintf(at_mqtt_sub_set, "AT+MQTTSUB=0,\"%s\",1\r\n", mqtt_topic_sub_set);
    sprintf(at_mqtt_sub_post, "AT+MQTTSUB=0,\"%s\",1\r\n", mqtt_topic_sub_post);

    // 定义MQTT主题、发布的数据和其他参数

    const char *mqtt_topic_pub_post = "/sys/h8w1VFUhcS3/share_car/thing/event/property/post";//这里需要改
    //const char *mqtt_data = //"{\\\"id\\\":\\\"122671964\\\"\\,\\\"params\\\":{\\\"car_clock\\\":0\\,\\\"GetLocation\\\":{\\\"altitude\\\":400\\,\\\"latitude\\\":66.546\\,\\\"OK\\\":1\\,\\\"longitude\\\":164.654}}\\,\\\"version\\\":\\\"1.0.0\\\"}";
    //"{\\\"params\\\":{\\\"LightSwitch\\\":1\\,\\\"temperature\\\":60\\,\\\"LightLuminance\\\":6.0}}";
    //
    char mqtt_data[200];
    //明天测试把这个放上去，进行数据的采集和上传
    //sprintf(mqtt_data,"{\\\"id\\\":\\\"122671964\\\"\\,\\\"params\\\":{\\\"car_lock\\\":%s\\,\\\"GetLocation\\\":{\\\"altitude\\\":%s\\,\\\"latitude\\\":%s\\,\\\"OK\\\":%s\\,\\\"longitude\\\":%s}}\\,\\\"version\\\":\\\"1.0.0\\\"}",public_car_lock,public_altitude,public_latitude,public_OK,public_longitude);
    //"
    //



    int qos = 0; // Quality of Service level
    int retain = 0; // Retain flag
    int message_id = 0; // Message ID, usually starts from 0 and increments for each new message

    // 使用sprintf构建AT+MQTTPUB命令
    sprintf(at_mqtt_pub_post, "AT+MQTTPUB=%d,\"%s\",\"%s\",%d,%d\r\n", message_id, mqtt_topic_pub_post, mqtt_data, qos,
            retain);

    int timeout_seconds = 1; // 读取响应的超时时间（秒）

    char *response = send_at_command(fd_cloud, at, timeout_seconds);
    if (response) {
        printf("Received: %s\n", response);
        free(response); // 释放响应字符串的内存
    } else {
        printf("Failed to send AT command or receive response.\n");
    }
    response = send_at_command(fd_cloud, at_rst, timeout_seconds);
    if (response) {
        printf("Received: %s\n", response);
        free(response); // 释放响应字符串的内存
    } else {
        printf("Failed to send AT command or receive response.\n");
    }

    response = send_at_command(fd_cloud, at_cwmode, timeout_seconds);
    if (response) {
        printf("Received: %s\n", response);
        free(response); // 释放响应字符串的内存
    } else {
        printf("Failed to send AT command or receive response.\n");
    }
    response = send_at_command(fd_cloud, at_cwjap, timeout_seconds + 3);
    if (response) {
        printf("Received: %s\n", response);
        free(response); // 释放响应字符串的内存
    } else {
        printf("Failed to send AT command or receive response.\n");
    }

    response = send_at_command(fd_cloud, at_mqtt_usercfg, timeout_seconds);
    if (response) {
        printf("Received: %s\n", response);
        free(response); // 释放响应字符串的内存
    } else {
        printf("Failed to send AT command or receive response.\n");
    }

    response = send_at_command(fd_cloud, at_mqtt_clientid, timeout_seconds);
    if (response) {
        printf("Received: %s\n", response);
        free(response); // 释放响应字符串的内存
    } else {
        printf("Failed to send AT command or receive response.\n");
    }

    response = send_at_command(fd_cloud, at_mqtt_conn, timeout_seconds);
    if (response) {
        printf("Received: %s\n", response);
        free(response); // 释放响应字符串的内存
    } else {
        printf("Failed to send AT command or receive response.\n");
    }
    response = send_at_command(fd_cloud, at_mqtt_sub_set, timeout_seconds);
    if (response) {
        printf("Received: %s\n", response);
        free(response); // 释放响应字符串的内存
    } else {
        printf("Failed to send AT command or receive response.\n");
    }

    response = send_at_command(fd_cloud, at_mqtt_sub_post, timeout_seconds);
    if (response) {
        printf("Received: %s\n", response);
        free(response); // 释放响应字符串的内存
    } else {
        printf("Failed to send AT command or receive response.\n");
    }

    response = send_at_command(fd_cloud, at_mqtt_pub_post, timeout_seconds + 3);
    if (response) {
        printf("Received: %s\n", response);
        free(response); // 释放响应字符串的内存
    } else {
        printf("Failed to send AT command or receive response.\n");
    }

    printf("********************************************\n");
    printf("开始传输GPS数据.......\n");



    /**********************************************/


    int i = 1;
    while (1) {
        // 读取GPS数据
        ssize_t len = read_from_serial(fd_gps, buffer, BUF_SIZE);  // 从GPS串口读取数据
        if (len > 0) {
            printf("GPS Data: %s\n", buffer);  // 打印读取到的GPS数据
            if (parse_gnrmc_data(buffer, &gpsData) == 0) { //如果等于0则证明读取到了数据

                printf("alt:%s",gpsData.altitude);
                printf("lati::%s",gpsData.latitude);
                printf("long:%s",gpsData.longitude);



                // 解析并处理GPS数据
                //构建参数
                sprintf(mqtt_data,
                        "{\\\"id\\\":\\\"122671964\\\"\\,\\\"params\\\":{\\\"car_lock\\\":%s\\,\\\"GetLocation\\\":{\\\"altitude\\\":%s\\,\\\"latitude\\\":%s\\,\\\"OK\\\":%s\\,\\\"longitude\\\":%s}}\\,\\\"version\\\":\\\"1.0.0\\\"}",
                        "1", gpsData.altitude, gpsData.latitude, gpsData.OK, gpsData.longitude);
                sprintf(at_mqtt_pub_post, "AT+MQTTPUB=%d,\"%s\",\"%s\",%d,%d\r\n", message_id, mqtt_topic_pub_post,
                        mqtt_data, qos, retain);
                response = send_at_command(fd_cloud, at_mqtt_pub_post, timeout_seconds + 3);

                if (response) {
                    printf("Received: %s\n", response);
                    free(response); // 释放响应字符串的内存
                } else {
                    printf("Failed to send AT command or receive response.\n");
                }

            }
        }
	
        //处理完数据，这里是发送数据的部分
        response = send_at_command(fd_cloud, at_mqtt_pub_post, timeout_seconds + 3);
        if (response) {
            printf("Received: %s\n", response);

            free(response); // 释放响应字符串的内存
            printf("第%d次数据传输完成\n", i);
            i++;
        } else {
            printf("Failed to send AT command or receive response.\n");
        }
        sleep(1);  // 根据实际需求设置合适的延迟时间
    }


    close(fd_cloud);  // 关闭云平台串口
    close(fd_gps);    // 关闭GPS串口

    return 0;  // 程序正常结束
}

